/**
 * C++ 安全漏洞检测查询
 * 基于CodeQL的source到sink模式检测常见安全漏洞
 * 
 * 输出列：
 *  - vulnerability_type: 漏洞类型
 *  - severity: 严重程度
 *  - source_location: 漏洞源位置
 *  - sink_location: 漏洞汇位置
 *  - description: 漏洞描述
 *  - remediation: 修复建议
 */

import cpp
import semmle.code.cpp.dataflow.DataFlow
import semmle.code.cpp.dataflow.TaintTracking

/**
 * 缓冲区溢出漏洞检测
 */
class BufferOverflowSource extends DataFlow::Node {
  BufferOverflowSource() {
    // 用户输入源
    exists(Parameter p | this.asParameter() = p) or
    // 网络接收
    exists(Call call |
      call.getTarget().hasQualifiedName("recv") and
      this.asExpr() = call
    ) or
    // 文件读取
    exists(Call call |
      call.getTarget().hasQualifiedName("fread") and
      this.asExpr() = call
    )
  }
}

class BufferOverflowSink extends DataFlow::Node {
  BufferOverflowSink() {
    // 不安全的字符串操作
    exists(Call call |
      call.getTarget().hasQualifiedName("strcpy") or
      call.getTarget().hasQualifiedName("strcat") or
      call.getTarget().hasQualifiedName("sprintf") or
      call.getTarget().hasQualifiedName("gets") and
      this.asExpr() = call
    )
  }
}

class BufferOverflowConfig extends TaintTracking::Configuration {
  BufferOverflowConfig() { this = "BufferOverflowConfig" }

  override predicate isSource(DataFlow::Node source) {
    source instanceof BufferOverflowSource
  }

  override predicate isSink(DataFlow::Node sink) {
    sink instanceof BufferOverflowSink
  }
}

/**
 * SQL注入漏洞检测
 */
class SQLInjectionSource extends DataFlow::Node {
  SQLInjectionSource() {
    // 用户输入参数
    exists(Parameter p | this.asParameter() = p) or
    // HTTP请求参数
    exists(Call call |
      call.getTarget().hasQualifiedName("getenv") and
      this.asExpr() = call
    )
  }
}

class SQLInjectionSink extends DataFlow::Node {
  SQLInjectionSink() {
    // SQL执行函数
    exists(Call call |
      call.getTarget().hasQualifiedName("sqlite3_exec") or
      call.getTarget().hasQualifiedName("mysql_query") or
      call.getTarget().hasQualifiedName("PQexec") and
      this.asExpr() = call
    )
  }
}

class SQLInjectionConfig extends TaintTracking::Configuration {
  SQLInjectionConfig() { this = "SQLInjectionConfig" }

  override predicate isSource(DataFlow::Node source) {
    source instanceof SQLInjectionSource
  }

  override predicate isSink(DataFlow::Node sink) {
    sink instanceof SQLInjectionSink
  }
}

/**
 * 命令注入漏洞检测
 */
class CommandInjectionSource extends DataFlow::Node {
  CommandInjectionSource() {
    // 用户输入
    exists(Parameter p | this.asParameter() = p) or
    // 环境变量
    exists(Call call |
      call.getTarget().hasQualifiedName("getenv") and
      this.asExpr() = call
    )
  }
}

class CommandInjectionSink extends DataFlow::Node {
  CommandInjectionSink() {
    // 系统命令执行
    exists(Call call |
      call.getTarget().hasQualifiedName("system") or
      call.getTarget().hasQualifiedName("popen") or
      call.getTarget().hasQualifiedName("exec") and
      this.asExpr() = call
    )
  }
}

class CommandInjectionConfig extends TaintTracking::Configuration {
  CommandInjectionConfig() { this = "CommandInjectionConfig" }

  override predicate isSource(DataFlow::Node source) {
    source instanceof CommandInjectionSource
  }

  override predicate isSink(DataFlow::Node sink) {
    sink instanceof CommandInjectionSink
  }
}

/**
 * 路径遍历漏洞检测
 */
class PathTraversalSource extends DataFlow::Node {
  PathTraversalSource() {
    // 用户输入
    exists(Parameter p | this.asParameter() = p) or
    // URL参数
    exists(Call call |
      call.getTarget().hasQualifiedName("getenv") and
      this.asExpr() = call
    )
  }
}

class PathTraversalSink extends DataFlow::Node {
  PathTraversalSink() {
    // 文件操作函数
    exists(Call call |
      call.getTarget().hasQualifiedName("fopen") or
      call.getTarget().hasQualifiedName("open") or
      call.getTarget().hasQualifiedName("CreateFile") and
      this.asExpr() = call
    )
  }
}

class PathTraversalConfig extends TaintTracking::Configuration {
  PathTraversalConfig() { this = "PathTraversalConfig" }

  override predicate isSource(DataFlow::Node source) {
    source instanceof PathTraversalSource
  }

  override predicate isSink(DataFlow::Node sink) {
    sink instanceof PathTraversalSink
  }
}

/**
 * 主查询：缓冲区溢出检测
 */
from BufferOverflowConfig config, DataFlow::Node source, DataFlow::Node sink
where
  config.hasFlow(source, sink)
select
  "BufferOverflow" as vulnerability_type,
  "High" as severity,
  source.getLocation().toString() as source_location,
  sink.getLocation().toString() as sink_location,
  "用户输入数据直接传递给不安全的字符串操作函数，可能导致缓冲区溢出" as description,
  "使用安全的字符串操作函数如strncpy、strncat、snprintf等，并确保缓冲区大小检查" as remediation

/**
 * SQL注入检测
 */
from SQLInjectionConfig config, DataFlow::Node source, DataFlow::Node sink
where
  config.hasFlow(source, sink)
select
  "SQLInjection" as vulnerability_type,
  "High" as severity,
  source.getLocation().toString() as source_location,
  sink.getLocation().toString() as sink_location,
  "用户输入直接拼接到SQL查询中，可能导致SQL注入攻击" as description,
  "使用参数化查询或预处理语句，避免直接拼接用户输入到SQL语句中" as remediation

/**
 * 命令注入检测
 */
from CommandInjectionConfig config, DataFlow::Node source, DataFlow::Node sink
where
  config.hasFlow(source, sink)
select
  "CommandInjection" as vulnerability_type,
  "Critical" as severity,
  source.getLocation().toString() as source_location,
  sink.getLocation().toString() as sink_location,
  "用户输入直接传递给系统命令执行函数，可能导致命令注入攻击" as description,
  "避免直接执行用户输入的命令，使用白名单验证或转义特殊字符" as remediation

/**
 * 路径遍历检测
 */
from PathTraversalConfig config, DataFlow::Node source, DataFlow::Node sink
where
  config.hasFlow(source, sink)
select
  "PathTraversal" as vulnerability_type,
  "Medium" as severity,
  source.getLocation().toString() as source_location,
  sink.getLocation().toString() as sink_location,
  "用户输入直接用作文件路径，可能导致路径遍历攻击" as description,
  "验证和清理文件路径，避免使用相对路径和特殊字符" as remediation
